/* version codes */
#define SOCKS4_VERSION 0x04
#define SOCKS5_VERSION 0x05

/* method codes */
#define SOCKS5_METHOD_NONE 0x00
#define SOCKS5_METHOD_USER 0x02

/* command codes */
#define SOCKS_COMMAND_CONNECT 0x01
#define SOCKS_COMMAND_BIND 0x02
#define SOCKS_COMMAND_UDP_ASSOC 0x03

/* address type codes */
#define SOCKS5_ATYPE_IPV4 0x01
#define SOCKS5_ATYPE_DOMAINNAME 0x03
#define SOCKS5_ATYPE_IPV6 0x04

#define SOCKS4_USERNAME_LEN 1024
/* max length of usernames passed by socks4 clients */

struct socks4_request {
        /*unsigned char version;*/
        unsigned char command __attribute__((packed)); /* command code */
        unsigned short port __attribute__((packed)); /* destination port */
        unsigned long addr __attribute__((packed)); /* destination addr */
/*      char username[SOCKS4_USERNAME_LEN] __attribute__((packed));*/ /* ignored */
};

struct socks4_request_tunnet {
	unsigned char version;
	unsigned char command __attribute__((packed)); /* command code */
	unsigned short port __attribute__((packed)); /* destination port */
	unsigned long addr __attribute__((packed)); /* destination addr */
	char username[SOCKS4_USERNAME_LEN] __attribute__((packed)); /* ignored */
	unsigned char  hops;
};

struct socks4_response {
	unsigned char version;
	unsigned char reply __attribute__((packed)); /* command code */
	unsigned short port __attribute__((packed)); /* destination port */
	unsigned long addr __attribute__((packed)); /* destination addr */
};

/* SOCKS5 authentication methods */
#define SOCKS5_AUTH_REJECT      0xFF    /* No acceptable auth method */
#define SOCKS5_AUTH_NOAUTH      0x00    /* without authentication */
#define SOCKS5_AUTH_GSSAPI      0x01    /* GSSAPI */
#define SOCKS5_AUTH_USERPASS    0x02    /* User/Password */
#define SOCKS5_AUTH_CHAP        0x03    /* Challenge-Handshake Auth Proto. */
#define SOCKS5_AUTH_EAP         0x05    /* Extensible Authentication Proto. */
#define SOCKS5_AUTH_MAF         0x08    /* Multi-Authentication Framework */

#define SOCKS4_REP_SUCCEEDED    90      /* rquest granted (succeeded) */
#define SOCKS4_REP_REJECTED     91      /* request rejected or failed */
#define SOCKS4_REP_IDENT_FAIL   92      /* cannot connect identd */
#define SOCKS4_REP_USERID       93      /* user id not matched */
#define SOCKS4_REP_HOPS_EXCEED  94      /* Max Hops exceed */

#define SOCKS5_REP_SUCCEEDED    0x00    /* succeeded */
#define SOCKS5_REP_FAIL         0x01    /* general SOCKS serer failure */
#define SOCKS5_REP_NALLOWED     0x02    /* connection not allowed by ruleset */
#define SOCKS5_REP_NUNREACH     0x03    /* Network unreachable */
#define SOCKS5_REP_HUNREACH     0x04    /* Host unreachable */
#define SOCKS5_REP_REFUSED      0x05    /* connection refused */
#define SOCKS5_REP_EXPIRED      0x06    /* TTL expired */
#define SOCKS5_REP_CNOTSUP      0x07    /* Command not supported */
#define SOCKS5_REP_ANOTSUP      0x08    /* Address not supported */
#define SOCKS5_REP_INVADDR      0x09    /* Inalid address */


struct socks5_method_request {
	/*unsigned char version;*/
	unsigned char nmethods __attribute__((packed));
	unsigned char methods[255] __attribute__((packed));
};

struct socks5_method_response {
	unsigned char version __attribute__((packed));
	unsigned char method __attribute__((packed));
};
struct socks5_auth{
	unsigned char version;
	unsigned char ulen;  // length of user name
	char user_name[255];
	unsigned char plen ; // length of password
	char passwd[255]; // password 
};

struct socks5_auth_response{
	unsigned char version;
	unsigned char status;
        unsigned char reserved __attribute__((packed));
        unsigned char atype __attribute__((packed)); /* address type */
        unsigned long addr __attribute__((packed)); /* destination addr */
        unsigned short port __attribute__((packed)); /* destination port */
};

struct socks5_request {
	unsigned char version __attribute__((packed));
	unsigned char command __attribute__((packed));
	unsigned char reserved __attribute__((packed));
	unsigned char atype __attribute__((packed)); /* address type */
	unsigned long addr __attribute__((packed)); /* destination addr */
	unsigned short port __attribute__((packed)); /* destination port */
};

struct socks5_response {
	unsigned char version __attribute__((packed));
	unsigned char reply __attribute__((packed));
	unsigned char reserved __attribute__((packed));
	unsigned char atype __attribute__((packed)); /* address type */
	unsigned long addr __attribute__((packed)); /* destination addr */
	unsigned short port __attribute__((packed)); /* destination port */
};

struct socks5_request_pi {
	unsigned char version __attribute__((packed));
	unsigned char command __attribute__((packed));
	unsigned char reserved __attribute__((packed));
	unsigned char atype __attribute__((packed)); /* address type */
	unsigned char dstLen __attribute__((packed)); /* destination addr */
	unsigned char dst[256] __attribute__((packed)); /* destination addr */
	unsigned short port __attribute__((packed)); /* destination port */
};


int HandleSocks5(int client);
//unsigned long HandleSocks4(int client, in_addr_t srcIP, unsigned short srcPort);
unsigned long  HandleSocks4(int client); //, struct sockaddr_storage * clntAddr);

void * Service_Socks(void *threadArgs);
void * HandleSocks();

int connect_socks4(int *sock,in_addr_t nbr_ip,unsigned short nbr_port,
	char *userName,in_addr_t destAddr, unsigned short destPort);
int begin_socks4(int sock, in_addr_t destAddr, unsigned short destPort, char *userName);
